#include "functions.h"

double evaluate( double *design_variables ){

	double value;
	
	if( strcmp( function_name, "Rastrigin") == 0 ){
	
	  value = rastrigin( design_variables );
	
	} else if( strcmp( function_name, "Rastrigin-1.0" ) == 0 ){

	  value = rastrigin_1( design_variables );

	} else if( strcmp( function_name, "RotatedRastrigin" ) == 0 ){
	
	  value = rotated_rastrigin( design_variables );
		
	} else if( strcmp( function_name, "Rosenbrock-Star" ) == 0 ){
	
	  value = rosenbrock_s( design_variables );
       
        } else if( strcmp( function_name, "Rosenbrock-Chain" ) == 0 ){

	  value = rosenbrock_c( design_variables );

	} else if( strcmp( function_name, "Schwefel" ) == 0 ){
	
	  value = schwefel( design_variables );
		
	} else if( strcmp( function_name, "Ridge" ) == 0 ){
	
	  value = ridge( design_variables );
		
	} else if( strcmp( function_name, "Griewank" ) == 0 ){
	
	  value = griewank( design_variables );
		
	} else if( strcmp( function_name, "Sphere" ) == 0 ){
	
	  value = sphere( design_variables );
	
	} else if( strcmp( function_name, "Ellipsoid" ) == 0 ){

	  value = ellipsoid( design_variables );
	  
	} else if( strcmp( function_name, "k-tablet" ) == 0 ){

	  value = ktablet( design_variables );

	} else if( strcmp( function_name, "Bohachevsky" ) == 0 ){

	  value = bohachevsky( design_variables );
	
	} else if( strcmp( function_name, "Ackley" ) == 0 ){

          value = ackley( design_variables );

	} else if( strcmp( function_name, "Schaffer" ) == 0 ){

	  value = schaffer( design_variables );

	} else if( strcmp( function_name, "f1") == 0 ){

          value = f1( design_variables );

	} else if( strcmp( function_name, "f2") == 0 ){

          value = f2( design_variables );

        } else if( strcmp( function_name, "f3") == 0 ){

          value = f3( design_variables );

        } else if( strcmp( function_name, "f7") == 0 ){

          value = f7( design_variables );

        } else if( strcmp( function_name, "f8") == 0 ){

          value = f8( design_variables );

	} else {

	  fprintf( stderr, "%s: invalid problem name\n", function_name );
	  exit( 2 );
	  
	}

	number_of_evaluations++;
	return value;
	
}

double f1( double *x ){
  int i;
  double y[ number_of_dimensions ];
  double sum = 0.0;

  for( i=0; i<number_of_dimensions; i++ )
    {
      if( i == 0 ){

	y[ i ] = x[ i ];

      } else{

	y[ i ] = x[ i ] + y[ i - 1 ];

      }
    }

  for( i=0; i<number_of_dimensions; i++ )
    {
      sum += fabs( y[ i ] );
    }

  return 100 / ( 10e-5 + sum );
}

double f2( double *x ){
  int i;
  double y[ number_of_dimensions ];
  double sum = 0.0;

  for( i=0; i<number_of_dimensions; i++ )
    {
      if( i == 0 ){

        y[ i ] = x[ i ];

      } else{

        y[ i ] = x[ i ] + sin( y[ i - 1 ] );

      }
    }

  for( i=0; i<number_of_dimensions; i++ )
    {
      sum += fabs( y[ i ] );
    }

  return 100 / ( 10e-5 + sum );
}

double f3( double *x ){
  int i;
  double y[ number_of_dimensions ];
  double sum = 0.0;

  for( i=0; i<number_of_dimensions; i++ )
    {
      y[ i ] = 0.024 * ( i + 2 ) - x[ i ];
    }

  for( i=0; i<number_of_dimensions; i++ )
    {
      sum += fabs( y[ i ] );
    }

  return 100 / ( 10e-5 + sum );
}

double f7( double *x ){
  int i;
  double sum = 0.0;

  for( i=0; i<number_of_dimensions; i++ )
    sum += -1 * x[ i ] * sin( sqrt( fabs( x[ i ] ) ) );

  return sum;
}

double f8( double *x ){
  int i;
  double sum = 0.0, sum2 = 1.0;

  for( i=0; i<number_of_dimensions; i++ )
    sum += pow( x[ i ], 2 );

  for( i=0; i<number_of_dimensions; i++ )
    sum2 = sum2 * cos( x[ i ] / sqrt( i + 2 ) );
  
  return sum - sum2;
  
}

double ellipsoid( double *x ){
  int i;
  double sum = 0.0;

  for( i=0; i<number_of_dimensions; i++ ){
    sum += pow( pow( 1000, (double)i / ( number_of_dimensions - 1 ) ) * x[ i ] , 2);
  }
  
  return sum;

}

double ktablet( double *x ){
  int i;
  int k = number_of_dimensions / 4;
  double sum = 0.0;

  for( i=0; i<k; i++)
    sum += x[ i ] * x[ i ];

  for( i=k+1; i<number_of_dimensions; i++ ){
    sum += 10000 * x[ i ] * x[ i ];

  }

  return sum;
}

double bohachevsky( double *x ){
  int i;
  double sum = 0.0;

  for( i=0; i<number_of_dimensions-1; i++ ){
    sum += x[ i ] * x[ i ] + 2 * x[ i + 1 ] * x[ i + 1 ] - 0.3 * cos( 3 * M_PI * x[ i ] ) - 0.4 * cos( 4 * M_PI * x[ i + 1 ] ) + 0.7;
  }

  return sum;
}

double ackley( double *x ){
  int i;
  double a = 0.0, b = 0.0, c = 0.0, d = 0.0;

  for( i=0; i<number_of_dimensions; i++ )
    a += x[ i ] * x[ i ];

  for( i=0; i<number_of_dimensions; i++ )
    b += cos( 2 * M_PI * x[ i ] );

  c = -0.2 * sqrt( 1.0 / number_of_dimensions * a );
  d = 1.0 / number_of_dimensions * b;

  return 20 - 20 * exp( c ) + M_E - exp( d );

}

double schaffer( double *x ){
  int i;
  double a, b;
  double sum = 0.0;

  for( i=0; i<number_of_dimensions-1; i++ ){
    a = pow( x[ i ] * x[ i ] + x[ i + 1 ] * x[ i + 1 ], 0.25 );
    b = 50 * pow( x[ i ] * x[ i ] + x[ i + 1 ] * x[ i + 1 ] , 0.1 );
    sum += a * ( pow( sin( b ), 2) + 1.0 );
  }

  return sum;

}

double rastrigin( double *x ){

	int i;
	double sum = 10 * number_of_dimensions;

	for( i = 0 ; i < number_of_dimensions ; i++ ){
    		sum += ( pow( x[ i ], 2 ) - 10 * cos( 2 * M_PI * x[ i ] ) );
  	}

	return sum;

}


double rastrigin_1( double *x ){

   int i;
   double sum = 10 * number_of_dimensions;

   for( i = 0 ; i < number_of_dimensions ; i++ ){
     sum += ( pow( ( x[ i ] - 1.0 ) , 2 ) - 10 * cos( 2 * M_PI * ( x[ i ] - 1.0 ) ) );
   }

   return sum;

 }

double rastrigin_n( double *x ){

	int i;
	double sum = 10 * number_of_dimensions;
	double parallel_translation = 2.0;

	for( i = 0 ; i < number_of_dimensions ; i++ ){
    		sum += ( pow( ( x[ i ] - parallel_translation ), 2 ) - 10 * cos( 2 * M_PI * ( x[ i ] - parallel_translation ) ) );
  	}

	return sum;

}

double rotated_rastrigin( double *x ){

	int i, j;
	double sum = 10 * number_of_dimensions;
	
	double *rotation, dtmp1, dtmp2;
	double cos_value = cos( M_PI * 1 / 3 );
	double sin_value = sin( M_PI * 1 / 3 );
	
	rotation = ( double * ) malloc( sizeof( double ) * number_of_dimensions );
	
	for( i = 0; i < number_of_dimensions; i++ ){
    		rotation[i] = x[ i ];
	}
	
	for( i = 0 ; i < ( number_of_dimensions - 1 ) ; i++ ){

    		for( j = i + 1 ; j < number_of_dimensions ; j++ ){

      		dtmp1 = cos_value * rotation[ i ] - sin_value * rotation[ j ];
      		dtmp2 = sin_value * rotation[ i ] + cos_value * rotation[ j ];
      		rotation[ i ] = dtmp1;
      		rotation[ j ] = dtmp2;

    		}
  	
  	}
  
	for( i = 0 ; i < number_of_dimensions ; i++ ){
    		sum += ( pow( rotation[ i ], 2 ) - 10 * cos( 2 * M_PI * rotation[ i ] ) );
  	}

	free( rotation );

	return sum;

}

double schwefel( double *x ){

 	static const double schw_ans = 418.98288727243379980791360139843;
 	
	int i;
  	double sum = 0;

	for( i = 0 ; i < number_of_dimensions; i++ ){
		
		    sum += x[ i ] * sin( sqrt( fabs( x[ i ] ) ) );
		
	}
	
  	sum += schw_ans * ( double ) number_of_dimensions;

  	return sum;

}

double rosenbrock_c( double *x ){

	int i;
	double sum = 0;

	for( i = 0 ; i < ( number_of_dimensions - 1 ); i++ ){
		sum += 100.0 * ( x[ i + 1 ] - x[ i ] * x[ i ] ) * ( x[ i + 1 ] - x[ i ] * x[ i ] ) + ( x[ i ] - 1 ) * ( x[ i ] - 1 );
	}
	
  	return sum;

}

double rosenbrock_s( double *x ){

  int i;
  double sum = 0;


  for( i = 1 ; i < number_of_dimensions; i++ ){                                                                                                 
    sum += 100.0 * ( x[ 0 ] - x[ i ] * x[ i ] ) * ( x[ 0 ] - x[ i ] * x[ i ] ) + ( x[ i ] - 1 ) * ( x[ i ] - 1 );                         
  }  

  return sum;

}


double griewank( double *x ) {
	
	int i;
 	double dtmp1 = 1, dtmp2 = 1;

	for( i = 0 ; i < number_of_dimensions ; i++ ) {
    		dtmp1 = dtmp1 + x[ i ] * x[ i ] / 4000;
	}
	
  	for( i = 0 ; i < number_of_dimensions ; i++ ) {
    		dtmp2 = dtmp2 * cos( x[ i ] / sqrt( i + 1 ) );
	}
  
  	dtmp1 = dtmp1 - dtmp2;

  	return dtmp1;

} 

double ridge( double *x ) {

	int i, j;
	double sum = 0, dtmp;
  
	for( i = 0 ; i < number_of_dimensions; i++ ){
		
    		dtmp = 0;
    		
    		for( j = 0 ; j <= i ; j++ ){
      		dtmp += x[ j ];
    		}
    		
    		sum += dtmp * dtmp;
  	}
  	
  	return sum;

}

double sphere( double *x ){

	int i;
	double sum = 0.0;
	
	for( i = 0; i < number_of_dimensions; i++ ){
	
		sum += x[ i ] * x[ i ];
	
	}

	return sum;
}

